﻿#ifndef __SS_ASIO_NETWORK_H__
#define __SS_ASIO_NETWORK_H__
#include "ssAsioThread.h"
#include "tools/ssIDAlloter.h"
#include "byteStream/ssWriteBytes.h"

namespace StarSeeker
{

class ssAsioNetWork
{
public:
	ssAsioNetWork(void);
	virtual~ssAsioNetWork(void);
	//参数配置
	void InitParam(const char *ip, const u16 port, u32 sessionCount, u32 threadCount, u32 recvBuffSize, u32 sendBuffSize);
	//启动网络服务
	bool StartNetWork(bool isClient);
	//尝试连接,客户端调用
	u32 ConnectToServer(u32 sessionId = 0);
	u32 ConnectToServer(u32 sessionId, const char *ip, const u16 port);
	void AasyncConnectToServer(u32 sessionId = 0);
	void AasyncConnectToServer(u32 sessionId, const char *ip, const u16 port);
	//停止网络服务并释放内存
	void StopNetWork();
	//是否有连接(作为客户时调用)
	bool IsConnect();
	//通知ASIO关闭连接
	void DoCloseSocket(u32 sessionId, eAsioClose errTypr, i32 err);
	//通知ASIO发送数据
	void DoSendData(u32 sessionId, char* buf, u32 len);
	void DoSendData(u32 sessionId, SS_SHARED_ARRAY<char>& buf, u32 len);
	void DoSendDataMulti(std::vector<u32>& sessionId, char* buf, u32 len);
	void DoSendDataAll(char* buf, u32 len);
	//客户端的SessionID(作为客户时调用)
	//virtual u32 GetClientID();
	//返回连接个数
	u32 GetSessionCount();
	//返回未处理完的发送请求次数
	lint GetSendEventCount();
	//返回发送队列总数
	lint GetSendQueueCount();
	//处理网络消息
	virtual void OnSessionMessage(ssAsioSession& session, u32 msgID, char* data);
	//设置线程名
	void SetThreadName(const char* name, const wchar_t* wname);
	//创建ASIO的地址结构
	static void MakeAddress(const char *ip, const u16 port, asio::ip::tcp::endpoint& out);
protected:
	//通知ASIO监听,新连接进入后要重复调用
	void DoAccept();
	//通知工作线程新Session创建
	void HandleAddSession(u32 threadId, ssAsioSessionPtr& ps);
	//通知ASIO接收数据,接收后要重复调用
	void DoReceive(ssAsioSessionPtr& ptr);
	//处理连接进入
	void HandleAccept(u32 sessionID, SS_SHARED_PTR<asio::ip::tcp::socket>& s, const asio::error_code& error);
	//处理连接关闭
	void HandleCloseSocket(u32 threadId, u32 sessionId, eAsioClose origin);
	//处理发送
	void HandleSendData(u32 threadId, u32 sessionId, SS_SHARED_ARRAY<char>& buf, u32 len);
	void HandleSendAll(u32 threadId, SS_SHARED_ARRAY<char>& buf, u32 len);
	//处理接收数据后
	void HandleAfterRead(const asio::error_code& error, size_t bytes, ssAsioSessionPtr& ps);
	//处理发送数据后
	void HandleAfterWrite(const asio::error_code& error, size_t bytes, ssAsioSessionPtr& ps, SS_SHARED_ARRAY<char>& buf);
	//处理连接服务器
	void HandleConnectToServer(const asio::error_code& error, u32 sessionID, SS_SHARED_PTR<asio::ip::tcp::socket>& s, SS_SHARED_PTR<asio::steady_timer>& timer);
	//发送一个数据包
	void SendOneData(bThreadPtr& pt, ssAsioSessionPtr& ps, SS_SHARED_ARRAY<char>& buf, u32 len);
	//发送队列所有数据包
	void SendSessionQueue(bThreadPtr& pt, ssAsioSessionPtr& ps);
	//连接断开后
	virtual void OnSessionClose(u32 sessionID){};
	//连接建立后
	virtual void OnNewSession(ssAsioSession& session){};
	//创建连接对象
	virtual ssAsioSession* CreateSession();
	//把包写入发送缓冲区
	virtual void WriteMsgIntoSendBuffer(SS_SHARED_ARRAY<char>& buf, u32& len);
	virtual void WriteMsgIntoSendBuffer(ssWriteBytes& wb, const char* data, u32 len);
protected:
	asio::ip::tcp::endpoint					m_listenAddr;		//监听地址
	bAcceptorPtr							m_acceptor;			//监听socket
	std::map<u32, asio::ip::tcp::endpoint>	m_connectionAddr;	//连接地址(多线程操作需要加锁)
	std::vector<bThreadPtr>					m_threads;			//网络线程
	u32										m_sessionCount;		//连接对象最大数量
	u32										m_threadCount;		//线程数量
	u32										m_recvBuffSize;		//接受缓冲大小
	u32										m_sendBuffSize;		//发送缓冲参考值
private:
	ssCumulationID<u32>						m_sessionID;		//连接编号源
	bool									m_isClient;			//作为客户端
	volatile bool							m_exiting;			//正在退出
public:
	bool									m_checkFullCount;	//是否检查接收缓冲区已满
	u32										m_autoConnectInterval;//自动重连间隔，秒
	std::string								m_netName;
};

}
#endif

